<html>
 <head>
  <meta charset="UTF-8">
 </head>
 <body>
  <h1 data-lake-id="vvjLV" id="vvjLV"><span data-lake-id="ub56adcac" id="ub56adcac">典型回答</span></h1>
  <p data-lake-id="u8d4b5a5c" id="u8d4b5a5c"><br></p>
  <p data-lake-id="uf4f3517a" id="uf4f3517a"><span data-lake-id="u90f6e28a" id="u90f6e28a">在Git中，merge和rebase是两种不同的代码合并策略，它们用于将一个分支的更改合并到另一个分支。它们的主要区别在于合并的方式和提交历史的表现上</span></p>
  <p data-lake-id="ue2f7db85" id="ue2f7db85"><span data-lake-id="u0d5aabcb" id="u0d5aabcb">​</span><br></p>
  <p data-lake-id="ud69706ea" id="ud69706ea"><span data-lake-id="u5681dd66" id="u5681dd66">在介绍区别之前，我们先看下当我们从主干（Main）创建了一个新的分支（Feature）开始开发代码时，然后另外有人把自己的代码提交到主干（Main）之后，就会产生分叉的提交记录。</span></p>
  <p data-lake-id="ub284a7b0" id="ub284a7b0"><span data-lake-id="u67c654bf" id="u67c654bf">​</span><br></p>
  <p data-lake-id="uc6f76670" id="uc6f76670"><img src="https://cdn.nlark.com/yuque/0/2023/png/5378072/1690091469933-03059138-036f-46fa-9153-3bcdf8438ecd.png?x-oss-process=image%2Fwatermark%2Ctype_d3F5LW1pY3JvaGVp%2Csize_36%2Ctext_SmF2YSA4IEd1IFA%3D%2Ccolor_FFFFFF%2Cshadow_50%2Ct_80%2Cg_se%2Cx_10%2Cy_10"></p>
  <p data-lake-id="u58ef7c6b" id="u58ef7c6b"><span data-lake-id="u3069243f" id="u3069243f">​</span><br></p>
  <p data-lake-id="u6ee7badf" id="u6ee7badf"><span data-lake-id="u2fab45d7" id="u2fab45d7">这时候你想把你的代码也提交到主干中，就有两个选择了：merge(合并)，rebase(变基)</span></p>
  <p data-lake-id="ua2a2422b" id="ua2a2422b"><span data-lake-id="u3f59f34e" id="u3f59f34e">​</span><br></p>
  <h2 data-lake-id="Si11v" id="Si11v"><span data-lake-id="uf90ebc68" id="uf90ebc68">merge</span></h2>
  <p data-lake-id="u3c666916" id="u3c666916"><br></p>
  <pre lang="java"><code>
git checkout feature
git merge main
</code></pre>
  <p data-lake-id="u4019e3ff" id="u4019e3ff"><br></p>
  <pre lang="java"><code>
git merge feature main
</code></pre>
  <p data-lake-id="u3f8c0ca4" id="u3f8c0ca4"><br></p>
  <p data-lake-id="ub9729342" id="ub9729342"><span data-lake-id="u4f22a2dc" id="u4f22a2dc">以上两种都是把一个主干(main)的最新代码合并(merge)到分支(featrue)的方式。</span></p>
  <p data-lake-id="ud46d4ca4" id="ud46d4ca4"><span data-lake-id="udbcf8ac3" id="udbcf8ac3">​</span><br></p>
  <p data-lake-id="u541e70d0" id="u541e70d0"><span data-lake-id="u0d7a1a5d" id="u0d7a1a5d">这个操作会在分支中创建一个新的“merge commit”，它将两个分支的更改合并到一个新的提交中。</span></p>
  <p data-lake-id="u58babf25" id="u58babf25"><span data-lake-id="u530534a7" id="u530534a7">​</span><br></p>
  <p data-lake-id="u1532d4e5" id="u1532d4e5"><img src="https://cdn.nlark.com/yuque/0/2023/png/5378072/1690094246537-d6fd3d83-56eb-4a53-bcca-c7bfdbf0feb4.png?x-oss-process=image%2Fwatermark%2Ctype_d3F5LW1pY3JvaGVp%2Csize_26%2Ctext_SmF2YSA4IEd1IFA%3D%2Ccolor_FFFFFF%2Cshadow_50%2Ct_80%2Cg_se%2Cx_10%2Cy_10"></p>
  <p data-lake-id="u88fb765a" id="u88fb765a"><br></p>
  <p data-lake-id="u8e3cfd2a" id="u8e3cfd2a"><span data-lake-id="ufa4364d8" id="ufa4364d8">如上图，就是我们把Main中的新提交Merge到我们的Feature分支中。</span></p>
  <p data-lake-id="u5325db13" id="u5325db13"><br></p>
  <h3 data-lake-id="hYxCK" id="hYxCK"><span data-lake-id="uee4276fc" id="uee4276fc">rebase</span></h3>
  <p data-lake-id="udb0ea37d" id="udb0ea37d"><br></p>
  <p data-lake-id="uc2d57dbc" id="uc2d57dbc"><span data-lake-id="uc1e53418" id="uc1e53418">作为merge的替代方法，您可以使用以下命令将功能分支重新设置为主分支：</span></p>
  <p data-lake-id="u3bb60232" id="u3bb60232"><span data-lake-id="ua99403ac" id="ua99403ac">​</span><br></p>
  <pre lang="java"><code>
git checkout main
git rebase feature
</code></pre>
  <p data-lake-id="u0a29bc82" id="u0a29bc82"><br></p>
  <p data-lake-id="u42b86160" id="u42b86160"><span data-lake-id="ua80bc3c9" id="ua80bc3c9">这会将整个main移动到feature分支的顶端，从而有效地将所有新提交合并到 feature 中。但是，rebase不是使用merge commit，而是通过为原始分支中的每个提交创建全新的提交来重写项目历史记录。</span></p>
  <p data-lake-id="u571bec87" id="u571bec87"><span data-lake-id="ub813c98e" id="ub813c98e">​</span><br></p>
  <p data-lake-id="u23c8ed66" id="u23c8ed66"><img src="https://cdn.nlark.com/yuque/0/2023/png/5378072/1690094295032-5e35a6bb-f42f-4deb-aa15-f41f90f43a02.png?x-oss-process=image%2Fwatermark%2Ctype_d3F5LW1pY3JvaGVp%2Csize_31%2Ctext_SmF2YSA4IEd1IFA%3D%2Ccolor_FFFFFF%2Cshadow_50%2Ct_80%2Cg_se%2Cx_10%2Cy_10"></p>
  <p data-lake-id="ubbb3fe4a" id="ubbb3fe4a"><br></p>
  <p data-lake-id="u54d554e1" id="u54d554e1"><span data-lake-id="u2f434fc1" id="u2f434fc1">如上图，就是我们将Main中新的提交，通过rebase的方式合并到我们的Feature分支中。</span></p>
  <p data-lake-id="u7f02c3dd" id="u7f02c3dd"><br></p>
  <h3 data-lake-id="PmMjv" id="PmMjv"><span data-lake-id="u5f07b613" id="u5f07b613">总结下区别</span></h3>
  <p data-lake-id="u97e22454" id="u97e22454"><br></p>
  <p data-lake-id="ub773647e" id="ub773647e"><span data-lake-id="u6493327a" id="u6493327a">当我们想要把一个分支合并到主干的时候，merge操作会通过merge commit的方式在主干上新建一个节点，并一次性的把分支中的修改合并到主干中。它的优点是分支代码合并后不破坏原分支的代码提交记录，缺点就是会产生额外的提交记录并进行两条分支的合并。</span></p>
  <p data-lake-id="ucb6ab544" id="ucb6ab544"><span data-lake-id="u8b53fb10" id="u8b53fb10">​</span><br></p>
  <p data-lake-id="u9c66f676" id="u9c66f676"><span data-lake-id="u52905dce" id="u52905dce">而rebase操作，不会在主干上新建节点，而是把分支上的所有历史提交都合并到主干中，形成一个完成的线性提交记录。他的优点是无须新增提交记录到目标分支，rebase后可以将对象分支的提交历史续上目标分支上，形成线性提交历史记录，进行review的时候更加直观。</span></p>
  <p data-lake-id="u8b85fe51" id="u8b85fe51"><span data-lake-id="uc936fed3" id="uc936fed3">​</span><br></p>
  <p data-lake-id="uce9f5610" id="uce9f5610"><span data-lake-id="u9d8d1c0a" id="u9d8d1c0a">所以，merge rebase可以保留完整的历史提交记录。</span></p>
  <p data-lake-id="u2491904f" id="u2491904f"><span data-lake-id="u5618a03f" id="u5618a03f">​</span><br></p>
  <p data-lake-id="ue470eca3" id="ue470eca3"><span data-lake-id="u6f6d3e3a" id="u6f6d3e3a">当你想要保留原始分支的提交历史，并且不介意在合并中产生额外的合并提交时，可以使用merge。在多人协作或公共分支上，merge是一个更安全和常见的选择，因为它保留了每个开发者的提交历史，易于跟踪和回溯。</span></p>
  <p data-lake-id="uc61f2d97" id="uc61f2d97"><span data-lake-id="u00bf0b11" id="u00bf0b11">​</span><br></p>
  <p data-lake-id="u1931ce64" id="u1931ce64"><span data-lake-id="u93a751dc" id="u93a751dc">当你想要保持提交历史的整洁、线性，并且愿意改写提交历史时，可以使用rebase。在个人开发分支上，为了保持提交历史的简洁和易于阅读，rebase用的更多。</span></p>
  <p data-lake-id="ubf35a24e" id="ubf35a24e"><br></p>
  <p data-lake-id="u6e06b7b3" id="u6e06b7b3"><span data-lake-id="ubef9e63b" id="ubef9e63b">一般来说，在公司内部做团队开发，使用merge的情况会更多一些，我在工作中基本上90%的时间都是使用merge的</span></p>
  <p data-lake-id="u6a3c0158" id="u6a3c0158"><span data-lake-id="u69ec4cb3" id="u69ec4cb3">​</span><br></p>
  <h1 data-lake-id="aw8JM" id="aw8JM"><span data-lake-id="u07bea5b0" id="u07bea5b0">扩展知识</span></h1>
  <p data-lake-id="u4176cadd" id="u4176cadd"><br></p>
  <h2 data-lake-id="elPhr" id="elPhr"><span data-lake-id="udbe4940f" id="udbe4940f">不建议在公共分支做rebase</span></h2>
  <p data-lake-id="uf1003cc6" id="uf1003cc6"><br></p>
  <p data-lake-id="u5fd62685" id="u5fd62685"><span data-lake-id="u2f275521" id="u2f275521">一般来说，我们在工作中的开发模式都是</span><strong><span data-lake-id="u19c213c1" id="u19c213c1">基于分支开发，基于主干发布</span></strong><span data-lake-id="u95edaeaa" id="u95edaeaa">的模式。什么意思呢？</span></p>
  <p data-lake-id="u636dfc74" id="u636dfc74"><span data-lake-id="uc674ca65" id="uc674ca65">​</span><br></p>
  <p data-lake-id="u7552151d" id="u7552151d"><span data-lake-id="u9a780dbf" id="u9a780dbf">就是仓库中有一份主干的代码，线上运行的就是这套代码，当我们有需求要开发的时候，不会直接在主干上开发，而是基于主干拉一个分支出来，在分支中进行开发，开发好之后，再把这个分支的代码通过发布的方式合并到主干中。</span></p>
  <p data-lake-id="u3e216e5d" id="u3e216e5d"><span data-lake-id="ufdd4dac9" id="ufdd4dac9">​</span><br></p>
  <p data-lake-id="uba9673fc" id="uba9673fc"><span data-lake-id="u0ddf7d21" id="u0ddf7d21">在业内有一个</span><strong><span data-lake-id="ua170a41b" id="ua170a41b">rebase黄金法则</span></strong><span data-lake-id="ub2d12b0a" id="ub2d12b0a">：</span><strong><span data-lake-id="u373c0a4b" id="u373c0a4b">不要对已经提交到共享仓库（如远程仓库）的提交执行 rebase。</span></strong></p>
  <p data-lake-id="u3c461bb2" id="u3c461bb2"><br></p>
  <p data-lake-id="uf620a8f5" id="uf620a8f5"><span data-lake-id="uca55d67d" id="uca55d67d">为什么要遵守这个黄金法则呢？</span></p>
  <p data-lake-id="u2c3a1d4d" id="u2c3a1d4d"><span data-lake-id="ubcd578ca" id="ubcd578ca">​</span><br></p>
  <p data-lake-id="u14a55270" id="u14a55270"><span data-lake-id="ub9430fb3" id="ub9430fb3">rebase会将所有的Main分支上的提交移动到Feature分支的顶端，问题是这个操作只发生在你自己的本地仓库中，所有的其他开发者是完全不感知的，因为他们是使用旧的Main分支创建的分支。</span></p>
  <p data-lake-id="ubc89321a" id="ubc89321a"><span data-lake-id="ub15a97c1" id="ub15a97c1">​</span><br></p>
  <p data-lake-id="uc9bf50dd" id="uc9bf50dd"><img src="https://cdn.nlark.com/yuque/0/2023/png/5378072/1690094700194-c03c80ba-cd08-4786-ae4f-64f68a61e14a.png?x-oss-process=image%2Fwatermark%2Ctype_d3F5LW1pY3JvaGVp%2Csize_29%2Ctext_SmF2YSA4IEd1IFA%3D%2Ccolor_FFFFFF%2Cshadow_50%2Ct_80%2Cg_se%2Cx_10%2Cy_10"></p>
  <p data-lake-id="u2229edd8" id="u2229edd8"><span data-lake-id="udc3b57c5" id="udc3b57c5">​</span><br></p>
  <p data-lake-id="uacc43801" id="uacc43801"><span data-lake-id="u85c53a51" id="u85c53a51">这时候如果我们的Feature变更被推送到远程仓库后，其他人的Feature想要在提交的时候，就会产生大量的冲突。</span></p>
  <p data-lake-id="u13fdab3b" id="u13fdab3b"><span data-lake-id="u6437ba08" id="u6437ba08">​</span><br></p>
  <p data-lake-id="u4089345e" id="u4089345e"><span data-lake-id="u47ce8238" id="u47ce8238">所以，在多人协作中，应该遵循以下指导原则：</span></p>
  <ol list="u4b1b561e">
   <li fid="uc9821b9f" data-lake-id="uee05d5c7" id="uee05d5c7"><span data-lake-id="u3c2d6bfa" id="u3c2d6bfa">在个人开发分支上进行 rebase：如果你在个人开发分支上进行 rebase，这不会对其他开发者产生影响，因为这个分支只属于你个人。</span></li>
   <li fid="uc9821b9f" data-lake-id="ub3d5ecdc" id="ub3d5ecdc"><span data-lake-id="u29fe8568" id="u29fe8568">在共享仓库的主分支上使用 merge：在共享仓库的主分支（如 master 或 main）上，推荐使用 merge 来将开发的功能或修复合并回主分支。这样可以保留每个开发者的提交历史，易于跟踪和回溯。</span></li>
   <li fid="uc9821b9f" data-lake-id="uefd397d3" id="uefd397d3"><span data-lake-id="uedf9f925" id="uedf9f925">协作时协商：如果有特殊情况需要在共享仓库的分支上进行 rebase，应该与其他开发者进行充分协商，并确保大家都知道并同意这个变更。</span></li>
  </ol>
 </body>
</html>